package gui;

import image.ImageCanvas;
import image.Layer;

import java.awt.Point;
import java.util.ArrayList;

import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Shape;

/**
 * A class which manages active Images
 * 
 * @author Etienne Bruines
 * @author Bas Dobbelsteen
 */
public class ImageManager
{
	private ArrayList<ImageCanvas> images;
	private TabPane tabs;

	private ImageCanvas activeImage;
	private Layer selectedLayer;

	private Settings settings;

	private int imageCounter;

	public ImageManager(Settings s)
	{
		images = new ArrayList<ImageCanvas>();
		tabs = new TabPane();
		settings = s;
		imageCounter = 0;

		activeImage = null;
		selectedLayer = null;
		open();
	}

	/**
	 * Opens a new / blank ImageCanvas TODO: allow for 'settings', such as width
	 * / height / background, etc.
	 */
	public void open()
	{
		ImageCanvas ic = new ImageCanvas(680, 604);
		ic.setTitle("Image " + ++imageCounter);
		setActiveImage(ic);
		open(ic);
	}

	public void open(String dir)
	{
		ImageCanvas ic = ImageCanvas.openFile(dir);
		open(ic);
	}

	public void open(final ImageCanvas ic)
	{
		// TODO: further open image canvas
		images.add(ic);

		Tab e = new Tab(ic.toString());

		e.setContextMenu(new TabContextMenu(e));

		ScrollPane sp = new ScrollPane();
		ic.getGroup().setStyle("-fx-background-color: " + Main.getBackground());
		sp.setContent(ic.getGroup());

		e.setContent(sp);
		tabs.getTabs().add(e);

		e.setOnSelectionChanged(new EventHandler<Event>()
		{
			@Override public void handle(Event event)
			{
				if (((Tab) event.getSource()).isSelected())
				{
					setActiveImage(ic);
					final Layer l = ic.getLayers().size() == 0 ? null : ic.getLayers().iterator().next();
					if (l != null)
						setSelectedLayer(l);
				}
			}
		});
		tabs.getSelectionModel().select(e);
	}

	private void setActiveImage(ImageCanvas ic)
	{
		activeImage = ic;
		// infoList.getItems().clear();
		// for (Layer l : ic.getLayers())
		// infoList.getItems().add(l.toString());

		activeImage.getGroup().setOnMouseDragged(new EventHandler<MouseEvent>()
		{
			@Override public void handle(MouseEvent event)
			{
				Mode mode = settings.getMode();
				if (settings.isDragging())
				{
					double width, height, x, y;
					switch (mode)
					{
					default:
						return;
					case Line:
						x = settings.getStartPoint().getX();
						y = settings.getStartPoint().getY();
						width = event.getX() - x;
						height = event.getY() - y;
						if (event.isShiftDown())
						{
							if (width > height)
								height = 0;
							else
								width = 0;
						}
						break;
					case Modify:
						if (activeImage.getActiveLayer() != null)
						{
							double xDif = event.getX() - settings.getStartPoint().getX();
							double yDif = event.getY() - settings.getStartPoint().getY();
							activeImage.getActiveLayer().getContent().setTranslateX(xDif);
							activeImage.getActiveLayer().getContent().setTranslateY(yDif);
						}
						return;
					case Triangle:
						ArrayList<Point> copy = new ArrayList<Point>(settings.trianglePoints());
						Point point = new Point();
						point.setLocation(event.getX(), event.getY());
						copy.add(point);
						activeImage.getGroup().getChildren().remove(settings.getSelectionShape());
						activeImage.getGroup().getChildren().add(settings.getSelectionShape(mode, copy));
						return;
					case Rectangle:
					case Text:
					case Ellipse:
						if (settings.getStartPoint().getX() > event.getX())
						{
							width = settings.getStartPoint().getX() - event.getX();
							x = event.getX();
						}
						else
						{
							width = event.getX() - settings.getStartPoint().getX();
							x = settings.getStartPoint().getX();
						}
						if (settings.getStartPoint().getY() > event.getY())
						{
							height = settings.getStartPoint().getY() - event.getY();
							y = event.getY();
						}
						else
						{
							height = event.getY() - settings.getStartPoint().getY();
							y = settings.getStartPoint().getY();
						}
						if (event.isShiftDown())
							height = width;
						break;
					}
					x -= activeImage.getGroup().getLocalToSceneTransform().getMxy();
					y -= activeImage.getGroup().getLocalToSceneTransform().getMyx();
					Shape selectShape = settings.getSelectionShape();
					image.Shape.resize(selectShape, mode, width, height);
					image.Shape.translate(selectShape, mode, x, y);
				}
				else if (mode != Mode.None)
				{

					Point p = new Point();
					p.setLocation(event.getX(), event.getY());
					settings.startDragging(p);
					if (mode == Mode.Triangle)
						settings.addTrianglePoint(p);
					if (mode == Mode.Modify)
						return;
					activeImage.getGroup().getChildren()
							.add(settings.getSelectionShape(mode, settings.trianglePoints()));
				}
			}

		});

		activeImage.getGroup().setOnMouseMoved(new EventHandler<MouseEvent>()
		{
			@Override public void handle(MouseEvent event)
			{
				Mode mode = settings.getMode();
				switch (mode)
				{
				default:
					return;
				case Triangle:
					if (settings.getTrianglePointCount() != 0)
					{
						ArrayList<Point> copy = new ArrayList<Point>(settings.trianglePoints());
						Point point = new Point();
						point.setLocation(event.getX(), event.getY());
						copy.add(point);
						activeImage.getGroup().getChildren().remove(settings.getSelectionShape());
						activeImage.getGroup().getChildren().add(settings.getSelectionShape(mode, copy));
					}
					break;
				}
			}
		});

		activeImage.getGroup().setOnMouseReleased(new EventHandler<MouseEvent>()
		{
			@Override public void handle(MouseEvent event)
			{
				// TODO: send event.getX(), event.getY(),
				// settings.getStartPoint().getX(),
				// settings.getStartPoint().getY() to the drawing thing
				double x, y, width, height;
				Mode mode = settings.getMode();
				switch (mode)
				{
				case None:
				case Modify:
					settings.stopDragging();
					if (activeImage.getActiveLayer() == null)
						return;
					Node c = activeImage.getActiveLayer().getContent();
					c.setLayoutX(c.getLayoutX() + c.getTranslateX());
					c.setLayoutY(c.getLayoutY() + c.getTranslateY());
					c.setTranslateX(0);
					c.setTranslateY(0);
					return;
				case Line:
					x = settings.getStartPoint().getX();
					y = settings.getStartPoint().getY();
					width = event.getX() - x;
					height = event.getY() - y;
					if (event.isShiftDown())
					{
						if (width > height)
							height = 0;
						else
							width = 0;
					}
					break;
				case Triangle:
					Point point = new Point();
					point.setLocation(event.getX(), event.getY());
					settings.addTrianglePoint(point);
					if (settings.getTrianglePointCount() >= 3)
					{
						activeImage.addLayer(Layer.getShape(settings, 0, 0, 0, 0));
						settings.trianglePoints().clear();
						settings.stopDragging();
						activeImage.getGroup().getChildren().remove(settings.getSelectionShape());
					}
					return;
				case Text:
					x = event.getX();
					y = event.getY();
					width = 0;
					height = 0;
					break;
				default:
					if (!settings.isDragging())
						return;
					if (event.getX() > settings.getStartPoint().getX())
					{
						x = settings.getStartPoint().getX();
						width = event.getX() - settings.getStartPoint().getX();
					}
					else
					{
						x = event.getX();
						width = settings.getStartPoint().getX() - event.getX();
					}
					if (event.getY() > settings.getStartPoint().getY())
					{
						y = settings.getStartPoint().getY();
						height = event.getY() - settings.getStartPoint().getY();
					}
					else
					{
						y = event.getY();
						height = settings.getStartPoint().getY() - event.getY();
					}
					if (event.isShiftDown())
						height = width;
					break;
				}
				Layer nieuwe = Layer.getShape(settings, x, y, width, height);
				activeImage.addLayer(nieuwe);
				if (mode == Mode.Text)
					nieuwe.getContent().requestFocus();
				settings.stopDragging();
				activeImage.getGroup().getChildren().remove(settings.getSelectionShape());
			}
		});
	}

	private void setSelectedLayer(Layer l)
	{
		selectedLayer = l;
	}

	public void close(ImageCanvas ic)
	{
		// TODO: further remove image canvas - ask for saving
		images.remove(ic);
	}

	public ImageCanvas getActiveImage()
	{
		return activeImage;
	}

	public Tab getCurrentTab()
	{
		return tabs.getSelectionModel().getSelectedItem();
	}

	public TabPane getTabPane()
	{
		return tabs;
	}
}
